﻿using MudBlazor.Utilities;

namespace MXERP.Blazor.Components
{
    /// <summary>
    /// Represents a vertical set of values.
    /// </summary>
    /// <typeparam name="T">The kind of item for this column.</typeparam>
    public abstract partial class Column<T> : MudComponentBase, IDisposable
    {

        internal readonly Guid uid = Guid.NewGuid();

        /// <summary>
        /// The data grid which owns this column.
        /// </summary>
        [CascadingParameter]
        public Table<T> Table { get; set; } = default!;

        /// <summary>
        /// The value stored in this column.
        /// </summary>
        [Parameter] public T Value { get; set; } = default!;

        /// <summary>
        /// Occurs when the <see cref="Value"/> has changed.
        /// </summary>
        [Parameter]
        public EventCallback<T> ValueChanged { get; set; }

        /// <summary>
        /// The display text for this column.
        /// </summary>
        [Parameter]
        public string? Title { get; set; }

        //internal string headerClassname =>
        //    new CssBuilder("mud-table-cell")
        //        .AddClass("sticky-left", StickyLeft)
        //        .AddClass("sticky-right", StickyRight)
        //        .AddClass(Class)
        //    .Build();

        //internal string footerClassname =>
        //    new CssBuilder("mud-table-cell")
        //        .AddClass(Class)
        //    .Build();

        [Parameter]
        public string? Width { get; set; }

        [Parameter]
        public string? MinWidth { get; set; }

        /// <summary>
        /// The template used to display this column's header.
        /// </summary>
        [Parameter]
        public RenderFragment<HeaderContext<T>>? HeaderTemplate { get; set; }

        /// <summary>
        /// The template used to display this column's value cells.
        /// </summary>
        [Parameter]
        public RenderFragment<CellContext<T>>? CellTemplate { get; set; }

        [Parameter]
        public bool StickyLeft { get; set; }

        [Parameter]
        public bool StickyRight { get; set; }

        [Parameter]
        public bool Ellipsis { get; set; }

        internal HeaderContext<T>? headerContext;

        internal string HeaderClassname =>
            new CssBuilder("md-table-cell")
                //.AddClass("sticky-left", StickyLeft)
                //.AddClass("sticky-right", StickyRight)
                .AddClass(Class)
            .Build();

        internal string CellStyle =>
            new StyleBuilder()
            .AddStyle("width", !string.IsNullOrWhiteSpace(Width)?(CssSizeLength)Width:"")
            .AddStyle(CalcFixedStyle())
            .AddStyle(Style)
            .Build();

        private StyleBuilder CalcFixedStyle()
        {
			if (!StickyLeft && !StickyRight)
            {
                return new StyleBuilder();
            }
            var fixedWidths = Array.Empty<string>();
            int colIndex = Table.RenderedColumns.IndexOf(this);
            if (StickyLeft)
            {
                for (int i = 0; i < colIndex; i++)
                {
                    var c = Table.RenderedColumns[i];
                    if (c.StickyLeft && !string.IsNullOrWhiteSpace(c.Width))
                        fixedWidths = fixedWidths.Append($"{(CssSizeLength)c.Width}");
                }
            }
            else if (StickyRight)
            {
                for (int i = Table.RenderedColumns.Count - 1; i > colIndex; i--)
                {
                    var c = Table.RenderedColumns[i];
                    if (c.StickyRight && !string.IsNullOrWhiteSpace(c.Width))
                        fixedWidths = fixedWidths.Append($"{(CssSizeLength)c.Width}");
                }
            }
            var fixedWidth = fixedWidths.Length switch
            {
                > 1 => $"calc({string.Join(" + ", fixedWidths)})",
                1 => fixedWidths[0],
                _ => "0px"
            };

            return new StyleBuilder()
                   .AddStyle("position", "sticky")
                   .AddStyle("left", fixedWidth, StickyLeft)
                   .AddStyle("right", fixedWidth, StickyRight && !StickyLeft)
                   .AddStyle("z-index", "1", StickyLeft || StickyRight);
        }

        public string CalcFixedClass()
        {
            int colIndex = Table.RenderedColumns.IndexOf(this);
            var stickyRightIndex = Table.RenderedColumns.FindIndex(x => x.StickyRight);
            var stickyLeftIndex = Table.RenderedColumns.FindLastIndex(x => x.StickyLeft);
            return new CssBuilder()
                .AddClass("md-table-cell-fix-right-first", stickyRightIndex == colIndex)
                .AddClass("md-table-cell-fix-left-last", stickyLeftIndex == colIndex)
                .Build();
        }

        protected override void OnInitialized()
        {
            base.OnInitialized();
            Table.AddColumn(this);
            headerContext = new HeaderContext<T>(Table);
        }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            await base.OnAfterRenderAsync(firstRender);
        }

        /// <summary>
        /// Releases resources used by this column.
        /// </summary>
        public virtual void Dispose()
        {
            Table.RemoveColumn(this);
        }

        #region Abstract Members


        protected internal virtual LambdaExpression? PropertyExpression { get; }


        /// <summary>
        /// The name of the property used for sorting this column's values.
        /// </summary>
        public virtual string? PropertyName { get; }

        protected internal abstract object? CellContent(T item);

        protected internal abstract object? PropertyFunc(T item);

        protected internal virtual Type? PropertyType { get; }

        protected internal abstract void SetProperty(object item, object value);

        #endregion
    }
}